package com.xxxx.paipaicars.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxxx.paipaicars.bean.UserDO;
import com.xxxx.paipaicars.bean.dto.UserDTO;
import com.xxxx.paipaicars.bean.vo.UserVO;
import com.xxxx.paipaicars.common.CommonConstant;
import com.xxxx.paipaicars.common.RandomNickConfig;
import com.xxxx.paipaicars.dao.UserMapper;
import com.xxxx.paipaicars.exception.BusinessException;
import com.xxxx.paipaicars.service.IUserService;
import com.xxxx.paipaicars.utils.BeanCopyUtil;
import com.xxxx.paipaicars.utils.JwtOperator;
import com.xxxx.paipaicars.utils.RedisUtil;
import com.xxxx.paipaicars.utils.SpringUtil;
import io.netty.util.internal.MathUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;

/**
 * Created by frank on 2023/2/14.
 */
@SuppressWarnings("all")
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements IUserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private RandomNickConfig randomNickConfig;

    // 注册的验证码池子前缀
    private static final String REGISTER_MSG_PREFIX = "register_msg_prefix_";
    // 忘记验证码的池子前缀
    private static final String FORGET_MSG_PREFIX = "forget_msg_prefix_";
    // 登录验证码的池子前缀
    private static final String LOGIN_MSG_PREFIX = "login_msg_prefix_";
    private static final String JWT_OPERATOR = "jwtOperator";


    @Override
    public Boolean register(UserDTO userDTO) {

        checkParamForRegister(userDTO);

        String msgCode = userDTO.getMsgCode();
        // 从缓存中获取注册手机号的验证码
        String redisCache = redisUtil.get(REGISTER_MSG_PREFIX + userDTO.getPhoneNumber());
        if (redisCache != msgCode) {
            throw new BusinessException("验证码错误");
        }
        // 插入数据
        UserDO userDO = new UserDO();
        userDO.setName(userDTO.getName());
        userDO.setPassword(userDTO.getPassword());
        userDO.setPhoneNumber(userDTO.getPhoneNumber());
        userMapper.insert(userDO);
        return true;
    }

    @Override
    public String sendMsgCode(UserDTO userDTO) {
        if (Objects.isNull(userDTO)) {
            throw new BusinessException("发送验证码实体为空");// 根据产品给出的提示
        }

        String phoneNumber = userDTO.getPhoneNumber();
        if (StringUtils.isBlank(phoneNumber)) {
            throw new BusinessException("手机号不能为空");
        }

        String source = userDTO.getSource();
        if (StringUtils.isBlank(source)) {
            throw new BusinessException("发送来源不能为空");
        }
        // select  * from user where phone_number = userDTO.getPhoneNumber();
//        userMapper.selectOne(new QueryWrapper<UserDO>().eq("phone_number",userDTO.getPhoneNumber()));
//        selectUserInfoByPhoneNumber(phoneNumber);
        if (!REGISTER_MSG_PREFIX.equals(source)) {
            UserDO userDO = selectUserInfoByPhoneNumber(phoneNumber);
        }
        // 准备短信验证码
        String uuid = UUID.randomUUID().toString().replace("-", "");
        redisUtil.set(userDTO.getSource() + phoneNumber, uuid);// 手机号 ---> uuid
        // todo 调用运营商的api发送短信
        return uuid;


    }


    @Override
    public Boolean updateUserPassword(UserDTO userDTO) {
        checkParamForUpdateUserPassword(userDTO);

        UserDO userDO = selectUserInfoByPhoneNumber(userDTO.getPhoneNumber());

        userDO.setPassword(userDTO.getPassword());
        //  update了所有列
        userMapper.update(userDO, new LambdaUpdateWrapper<UserDO>()
                .eq(UserDO::getPhoneNumber, userDTO.getPhoneNumber()));

        return true;

    }

    @Override
    public UserVO loginByMsgCode(UserDTO userDTO) {
        checkParamForLogin(userDTO);

        // 校验验证码是否正确
        String msgCode = userDTO.getMsgCode();
        String redisCache = redisUtil.get(LOGIN_MSG_PREFIX + userDTO.getPhoneNumber());
        if (!msgCode.equals(redisCache)) {
            throw new BusinessException("登录验证码输入错误");
        }

        String phoneNumber = userDTO.getPhoneNumber();
        UserDO userDO = selectUserInfoByPhoneNumber(phoneNumber);
        // todo jwt
        //TODO:使用Spring上下文进行注入
        JwtOperator jwtOperator = SpringUtil.getBean(JWT_OPERATOR);
        Map<String,Object> UserInfoMap = new HashMap<>();
        //存放用户信息
        UserInfoMap.put(CommonConstant.PHONE_NUMBER,phoneNumber);
        UserInfoMap.put(CommonConstant.OTHER_INFO,userDO);
        //生成对应的Token 并且存入到Redis里面
        String token = jwtOperator.generateToken(UserInfoMap);
        UserVO userVO = BeanCopyUtil.copyProperties(userDO, UserVO.class);
        userVO.setToken(token);
        // 放入到缓存中
        redisUtil.set(CommonConstant.TOKEN_PREFIX+phoneNumber, token);

        return userVO;
    }

    @Override
    public Boolean logout(UserDTO userDTO) {
        if (Objects.isNull(userDTO)) {
            throw new BusinessException("退出登录实体为空");// 根据产品给出的提示
        }
        if (StringUtils.isBlank(userDTO.getPhoneNumber())) {
            throw new BusinessException("手机号不能为空");
        }

        redisUtil.delete(LOGIN_MSG_PREFIX + userDTO.getPhoneNumber());
        return true;
    }

    private void checkParamForLogin(UserDTO userDTO) {
        if (Objects.isNull(userDTO)) {
            throw new BusinessException("登录实体为空");// 根据产品给出的提示
        }

        if (StringUtils.isBlank(userDTO.getPhoneNumber())) {
            throw new BusinessException("登录手机号不能为空");
        }
        // todo 手机号非法性校验
        if (StringUtils.isBlank(userDTO.getMsgCode())) {
            throw new BusinessException("登录短信验证码不能为空");
        }
    }

    /**
     * 参数校验
     *
     * @param userDTO 通用实体
     */
    private void checkParamForRegister(UserDTO userDTO) {

        if (Objects.isNull(userDTO)) {
            throw new BusinessException("注册实体为空");// 根据产品给出的提示
        }
        if (StringUtils.isBlank(userDTO.getName())) {
            userDTO.setName(randomNickConfig.swichOne());

        }
        String password = userDTO.getPassword();
        if (StringUtils.isBlank(password)) {
            throw new BusinessException("密码不能为空");
        }
        String conformPassword = userDTO.getConformPassword();
        if (StringUtils.isBlank(conformPassword)) {
            throw new BusinessException("确认密码不能为空");
        }
        if (!password.equals(conformPassword)) {
            throw new BusinessException("密码输入不一致");
        }
        if (StringUtils.isBlank(userDTO.getPhoneNumber())) {
            throw new BusinessException("手机号不能为空");
        }
        // todo 手机号非法性校验
        if (StringUtils.isBlank(userDTO.getMsgCode())) {
            throw new BusinessException("短信验证码不能为空");
        }


        // 推荐用下面的方式来做
//        Assert.notNull(userDTO, "注册实体为空");
    }


    /**
     * 参数校验
     *
     * @param userDTO 通用实体
     */
    private void checkParamForUpdateUserPassword(UserDTO userDTO) {

        if (Objects.isNull(userDTO)) {
            throw new BusinessException("注册实体为空");// 根据产品给出的提示
        }
        if (StringUtils.isBlank(userDTO.getPhoneNumber())) {
            throw new BusinessException("手机号不能为空");
        }
        String password = userDTO.getPassword();
        if (StringUtils.isBlank(password)) {
            throw new BusinessException("密码不能为空");
        }
        String conformPassword = userDTO.getConformPassword();
        if (StringUtils.isBlank(conformPassword)) {
            throw new BusinessException("确认密码不能为空");
        }
        if (!password.equals(conformPassword)) {
            throw new BusinessException("密码输入不一致");
        }
    }

    /**
     * 通过手机号查询用户信息
     *
     * @param phoneNumber 手机号
     * @return 用户信息
     */
    private UserDO selectUserInfoByPhoneNumber(String phoneNumber) {
        UserDO userDO = userMapper.selectOne(new LambdaQueryWrapper<UserDO>()
                .eq(UserDO::getPhoneNumber, phoneNumber));
        if (Objects.isNull(userDO)) {
            throw new BusinessException("未查询到当前用户");
        }

        return userDO;
    }

}
